﻿#pragma once
#include "XyNet/Crypto/CryptoPP.h"

namespace XyNet
{
	/// Aes加解密器
	class XYNET_API Aes : noncopyable
	{
	public:
		/// 密钥类型
		enum KeyType
		{
			AesDefault = 0,	// 默认Aes128
			Aes128 = 128,
			Aes192 = 192,
			Aes256 = 256
		};

	public:
		/// 以密钥类型初始化随机密钥
		Aes(KeyType keyType = AesDefault);
		/// 用key和iv初始化（key和iv都会被摘要到合适的长度）
		Aes(const Bytes& key, const Bytes& iv = "");

		/// 获取密钥类型
		KeyType getKeyType() const;
		/// 设置密钥类型，并随机生成密钥
		void setKeyType(KeyType keyType);

		/// 获取key
		const Bytes& getKey() const;
		/// 获取密钥字节大小
		int getKeyByteLength() const;
		/// 获取密钥位大小
		int getKeyBitLength() const;

		/// 获取初始向量
		const Bytes& getIv() const;
		/// 获取初始向量字节大小
		int getIvByteLength() const;
		/// 获取初始向量位大小
		int getIvBitLength() const;

		/// 设置指定key和iv（key和iv都会被摘要到合适的长度）
		void setKeyAndIv(const Bytes& key, const Bytes& iv = "");
		/// 设置iv
		void setIv(const Bytes& iv);
		/// 设置随机iv
		void setRandomIv();

		/// 加密
		Bytes encrypt(const Bytes& input);
		/// 解密
		Bytes decrypt(const Bytes& input);

		/// 获取默认密钥类型
		static KeyType getDefaultKeyType();
		/// 设置默认密钥类型
		static void setDefaultKeyType(KeyType keyType);

	private:
		/// 应用key和iv，将值赋予加密器和解密器
		void applyKeyAndIv();

	private:
		/// 加密器，综合考虑OFB模式比较好
		CryptoPP::OFB_Mode<CryptoPP::AES>::Encryption _encryptor;
		/// 解密器，综合考虑OFB模式比较好
		CryptoPP::OFB_Mode<CryptoPP::AES>::Decryption _decryptor;
		/// 密钥类型
		KeyType _keyType;
		/// 密钥
		Bytes _key;
		/// 初始向量
		Bytes _iv;

		/// 默认密钥类型
		static KeyType _defaultKeyType;
		/// IV长度
		static const int _ivByteLength;
	};
}

//////////////////////////////////////////////////////////////////////////

namespace XyNet
{
	extern "C"
	{
		/// 创建Aes对象
		XYNET_API Aes* AesCreateWithKeyType(Aes::KeyType keyType);
		/// 创建Aes对象
		XYNET_API Aes* AesCreateWithKeyAndIv(Bytes* key, Bytes* iv);
		/// 销毁Aes对象
		XYNET_API void AesDestroy(Aes* aes);

		/// 获取Aes密钥类型
		XYNET_API Aes::KeyType AesGetKeyType(Aes* aes);
		/// 设置Aes密钥类型，同时生成随机密钥
		XYNET_API void AesSetKeyType(Aes* aes, Aes::KeyType keyType);

		/// 获取密钥
		XYNET_API Bytes* AesGetKey(Aes* aes);
		/// 获取iv
		XYNET_API Bytes* AesGetIv(Aes* aes);
		/// 设置指定key和iv（key和iv都会被摘要到合适的长度）
		XYNET_API void AesSetKeyAndIv(Aes* aes, Bytes* key, Bytes* iv);

		/// 加密
		XYNET_API Bytes* AesEncrypt(Aes* aes, Bytes* input);
		/// 解密
		XYNET_API Bytes* AesDecrypt(Aes* aes, Bytes* input);

		/// 获取默认密钥类型
		XYNET_API Aes::KeyType AesGetDefaultKeyType();
		/// 设置默认密钥类型
		XYNET_API void AesSetDefaultKeyType(Aes::KeyType keyType);
	}
}